package tpoo.server.model;

import static tpoo.common.services.utils.ServiceConstants.CODEC_SERVICE;

import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.util.Observable;
import java.util.Observer;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import tpoo.common.services.exceptions.ServiceException;
import tpoo.common.services.utils.ServiceAdmin;
import tpoo.common.utils.codec.Codec;
import tpoo.common.utils.passiveOperations.NotValidPassiveOperation;
import tpoo.common.utils.passiveOperations.PassiveOperation;
import tpoo.server.model.users.User;

/**
 * Esta clase es la representación de un cliente conectado al servidor
 * Responsabilidad:
 * 	Comunicar las operaciones al cliente que corresponda (conoce la ip y el puerto al cual notificar)
 * @author diego
 *
 */
public class Client implements Observer {

	private static Log logger = LogFactory.getLog(Client.class);

	private User user;
	private InetAddress ip;
	private Integer port;

	public Client(User user, InetAddress ip, Integer port) {
		super();
		this.setUser(user);
		this.setIp(ip);
		this.setPort(port);
		user.addObserver(this);
	}

	private void setIp(InetAddress ip) {
		this.ip = ip;
	}

	public InetAddress getIp() {
		return ip;
	}

	private void setUser(User user) {
		this.user = user;
	}

	public User getUser() {
		return user;
	}

	private void setPort(Integer port) {
		this.port = port;
	}

	public Integer getPort() {
		return port;
	}

	/**
	 * En arg se espera una Operacion Pasiva (@see {@link PassiveOperation})
	 */
	public void update(Observable o, Object aPassiveOperation) {
		try {
			if (! (aPassiveOperation instanceof PassiveOperation))
				aPassiveOperation = new NotValidPassiveOperation(aPassiveOperation.toString()); 
			
			logger.debug("Avisando a "+ getUser() +"@"+ this.getIp() + ":" + this.getPort());
			Socket s = new Socket(this.getIp(), this.getPort());
						
			Codec codec = (Codec) ServiceAdmin.getService(CODEC_SERVICE);
			codec.code(aPassiveOperation, s.getOutputStream());
			s.getOutputStream().flush();
			s.close();
		} catch (IOException e) {
			e.printStackTrace();
			logger.fatal(e.getMessage(), e);
		} catch (ServiceException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	@Override
	protected void finalize() throws Throwable {
		getUser().logout();
		getUser().deleteObserver(this);
		logger.debug("Finalizing the "+ getUser()+"'s client");
		super.finalize();
	}

	@Override
	public String toString() {
		return this.getUser() + "@" + this.getIp() + ":" + this.getPort();
	}
}
